package pl.smath.worksheet;

import java.util.ArrayList;
import java.util.List;

import pl.smath.expression.MultiTerm;
import pl.smath.expression.Term;
import pl.smath.operation.BasicOp;
import pl.smath.parser.ExpressionParser;
import pl.smath.worksheet.results.OneStep;
import pl.smath.worksheet.results.Resolution;



/**
 * Podaje rozwiązanie wyrażenia krok po kroku.
 * @author Piotr Mech
 *
 */
public class ResolveExpression {

	public enum EquationType { Simplify }
	
	private Resolution resolution = new Resolution();
	private Resolution bestResolution = new Resolution();
	private int bestScore = 1000;
	
	
	/**
	 * Dokonuje szeregu przekształceń wyrażenia i zwraca je w postaci obiektu Resolution
	 * 
	 * @param inputExpression
	 * @return
	 */
	public Resolution resolve(String expression, EquationType type){

		ExpressionParser parser = new ExpressionParser();
		Term term = parser.parseText( expression );
		
		if (type == EquationType.Simplify)
			return simplifyExpression(term);

		return null;
	}
	
	private Resolution simplifyExpression(Term term){
		
		resolution = new Resolution();
		resolution.addStep(new OneStep(term, "Zadanie: Uprościć wyrażenie"));
		tryAllCombinations(resolution, term);
		
		return bestResolution;
	}
	
	private boolean isMulti(Term term){
		if (term instanceof MultiTerm )
			return false;
		return true;
	}
	
	private List<Terms> getTermCombinations(List<Term> list){
		List<Terms> terms = new ArrayList<Terms>();
		
		for (int i = 0; i<list.size()-1; i++){
			for (int j=i+1; j<list.size(); j++){
				Term t1 = list.get(i);
				Term t2 = list.get(j);
				terms.add(new Terms(t1, t2));
			}	
		}
		return terms;
	}
	
	private Term tryAllCombinations(Resolution resolution, Term term){
		
		Resolution newResolution = resolution.copy();
		
		if (term instanceof MultiTerm ){
			MultiTerm multi = (MultiTerm)term;
			List<Term> list = multi.getTermsList();
			List<Terms> terms = getTermCombinations(list);
			
			boolean isLastMulti = true;
			for(Terms childPair: terms){
				Term t1 = childPair.t1;
				Term t2 = childPair.t2;
				
				if (isMulti(childPair.t1)){
					t1 = tryAllCombinations(resolution, childPair.t1);
				}
				if (isMulti(childPair.t2)){
					t2 = tryAllCombinations(resolution, childPair.t2);
				}
					
				Term t = BasicOp.add(t1, t2);
				if (!t.isTheSame(term)){
					newResolution.addStep(new OneStep(t, 
							String.format("dodajemy {0} i {1}", t1.getText(), t2.getText())));
					return t;
				}
			}
		}
		
		
		//Resolution newResolution = resolution.Copy();
		return term;
	}
	
//	/**
//	 * Oblicza liczbe wszystkich węzłów w danym nodzie.
//	 * 
//	 * @param node
//	 * @return liczba węzłów
//	 */
//	private int nodesCount(Node node){
//		
//		int count = 1;
//		
//		if (node.getFirstChild() != null){
//			count += nodesCount(node.getFirstChild());
//		}
//		if (node.getSecondChild() != null){
//			count += nodesCount(node.getSecondChild());
//		}
//		
//		return count;
//	}
//	
//	/**
//	 * Oblicza jakość rozwiązania na podstawie ilości wezłów wyrażenia w postaci końcowej.
//	 * 
//	 * @param resolution
//	 * @return score
//	 */
//	private int evaluate(Resolution resolution){
//		OneStep step = resolution.last();
//		return nodesCount(step.getNode());
//	}
//	
//	/**
//	 * Rekurencyjnie sprawdza wszystkie mozliwe transofrmacje dla podanego wyrażenia.
//	 * Kombinacja prowadząca do najmniejszego drzewa jest naszym poszukiwanym rozwiązaniem.
//	 * 
//	 * @param resolution
//	 * @param node
//	 */
//	private void tryAllCombinations(Resolution resolution, Node node){
//		
//		Resolution newResolution = resolution.Copy();
//		
//		Node newNode = node.transform(new AddTransform());
//		if (!newNode.isTheSame(node)){
//			newResolution.addStep(new OneStep(newNode, "Dodajemy składniki"));
//			tryAllCombinations(newResolution, newNode);
//			return;
//		}
//		newNode = node.transform(new MultiplyTransform());
//		if (!newNode.isTheSame(node)){
//			newResolution.addStep(new OneStep(newNode, "Mnożymy składniki"));
//			tryAllCombinations(newResolution, newNode);
//			return;
//		}
//		newNode = node.transform(new MultiAddTransform());
//		if (!newNode.isTheSame(node)){
//			newResolution.addStep(new OneStep(newNode, "Wymnażamy wyrażenia w nawiasach"));
//			tryAllCombinations(newResolution, newNode);
//			return;
//		}
//		newNode = node.transform(new PowerMultiplyTransform());
//		if (!newNode.isTheSame(node)){
//			newResolution.addStep(new OneStep(newNode, "Podnosimy iloczyny do potęgi"));
//			tryAllCombinations(newResolution, newNode);
//			return;
//		}
//		
//		int score = evaluate(resolution);
//		if (score < bestScore){
//			bestResolution = resolution;
//			bestScore = score;
//		}
//		
//		return;
//	}
//	
//	
//	private Resolution simplifyExpression(Node node){
//		
//		resolution = new Resolution();
//		resolution.addStep(new OneStep(node, "Zadanie: Uprościć wyrażenie"));
//		tryAllCombinations(resolution, node);
//		
//		return bestResolution;
//	}
//	
//	public Resolution getResolution(){
//		
//		return resolution; 
//	}
//	
//	/**
//	 * Dokonuje szeregu przekształceń wyrażenia i zwraca je w postaci obiektu Resolution
//	 * 
//	 * @param inputExpression
//	 * @return
//	 */
//	public Resolution resolve(String inputExpression, EquationType type){
//
////		ExpressionParser parser = new ExpressionParser();
////		Node node = parser.parseAST(inputExpression);
////		
////		if (type == EquationType.Simplify)
////			return simplifyExpression(node);
//
//		return null;
//	}
}


final class Terms{
	public Term t1;
	public Term t2;
	
	public Terms(Term t1, Term t2){
		this.t1 = t1;
		this.t2 = t2;
	}
}